from duckserver.models import User
from duckserver.models import Work, Comment
from duckserver.models import Tagwork
from duckserver.models import Community, Grouprelation
from duckserver.models import Tagreflect, WorkImg
from duckserver.models import Follow, Payrelation, Likerelation
import time
from django.db.models.aggregates import Sum, Count
from django.conf import settings
from django.core.paginator import Paginator, InvalidPage, EmptyPage, PageNotAnInteger
from duckserver.service.duckPowerEgg import costPower

from duckserver.service.user import getUserInfo
from duckserver.service.community import getGroupMessage
import datetime

# 发帖POST
'''
{
    "userid": 1000001,
    "text": "这是一条帖子",
    "title": "标题1",
    "getPaid": 50,
    "groupid": 1,
    "tag": [
        "tag1",
        "tag2"
    ]
}
'''


def postWork(userid, title, text, getPaid, groupid, tags, imgList):
    response = {'workid': 0, 'ok': 0, 'msg': ''}
    if costPower(userid, 10):
        user = User.objects.get(userid=userid)
        group = Community.objects.get(groupid=groupid)

        if getPaid is None or getPaid == "":
            getPaid = 0
        work = Work(userid=user, groupid=group,
                    getpaid=getPaid, title=title, text=text)
        work.save()

        # tag相关
        for tag in tags:
            if tag == "":
                continue
            cur_tag = Tagreflect.objects.get_or_create(tag=tag)[0]
            cur_tag.save()
            Tagwork(tagid=Tagreflect(cur_tag.tagid), workid=work).save()

        # 处理图片
        i = 0
        for img in imgList:
            workimg = WorkImg(workid=work, image=img)
            workimg.save()
            i += 1
        work.imagenum = i
        work.save()

        response['workid'] = work.workid
        response['ok'] = 1
    else:
        response['msg'] = "鸭力不足"
    return response


# 删帖
def deleteWork(workid):
    response = {'ok': 0, 'msg': ''}

    work = Work.objects.get(workid=workid)
    work.status = 1
    work.save()

    response['ok'] = 1
    return response


# 获取帖子详情
def getWorkInfo(userid, workid, mode=0):
    '''
    mode: 默认0，为1时返回列表所需要信息
    '''
    user = User.objects.get(userid=userid)
    work = Work.objects.get(workid=workid)

    response = {'ok': 0, 'msg': ''}

    # 帖子作者
    response['userId'] = work.userid_id
    response['userName'] = work.userid.username
    response['userImg'] = settings.ROOT_URL + work.userid.headImage.url
    response['workid'] = work.workid

    # 用户相关
    fol = Follow.objects.filter(userid=work.userid, follower=user)
    response['isFollow'] = bool(len(fol))
    pay = Payrelation.objects.filter(userid=user, workid=work)
    response['isPaied'] = bool(len(pay))

    # 作者本人设为已购买
    if work.userid_id == userid:
        response['isPaied'] = True

    like = Likerelation.objects.filter(userid=user, workid=work)
    response['isLike'] = bool(len(like))

    # 帖子正文
    response['title'] = work.title
    response['needPay'] = bool(work.getpaid)
    response['needNum'] = work.getpaid

    # 展示全文
    if response['needPay'] is False or response['isPaied'] is True:
        response['detailContent'] = work.text
        response['content'] = ''
    else:
        # 仅显示摘要
        response['detailContent'] = ''
        response['content'] = "%.100s..." % work.text

    # 帖子相关数据
    response['likeNum'] = work.attitudenum
    response['commentNum'] = work.commentnum
    response['shareNum'] = work.sharenum
    response['releasetime'] = work.releasetime

    # 评论相关
    comments = Comment.objects.filter(rootknot=work)
    commentList = []
    i = 0
    for comment in comments:
        i += 1
        obj = {'id': i, 'type': 0}
        obj['userId'] = comment.userid_id
        obj['userName'] = comment.userid.username
        obj['commentId'] = comment.commentid
        obj['content'] = comment.content

        # @开头表示原帖评论
        if comment.commentparentid[0] != '@':
            # 楼中楼
            obj['type'] = 1
            obj['parentId'] = int(comment.commentparentid)
            parent_comment = Comment.objects.get(
                commentid=comment.commentparentid)
            obj['parentUserId'] = parent_comment.userid_id
            obj['parentUserName'] = parent_comment.userid.username
        commentList.append(obj)
    response['commentList'] = commentList

    if mode == 1:   # 列表模式只返回前三条
        response['commentList'] = commentList[:min(3, len(commentList))]
        # 50字简介
        response['postAbstract'] = "%.50s..." % work.text
        response.pop('content')
        response.pop('detailContent')

    # Tag 相关
    tags = Tagwork.objects.filter(workid=work)
    tagList = []
    i = 0
    for tag in tags:
        i += 1
        obj = {'id': i}
        obj['tag'] = tag.tagid.tag
        obj['tagId'] = tag.tagid_id
        tagList.append(obj)
    response['tagList'] = tagList

    # 图片相关
    response['imgNum'] = work.imagenum
    imgs = WorkImg.objects.filter(workid=work)
    images = []
    for img in imgs:
        images.append(settings.ROOT_URL + img.image.url)
    response['images'] = images

    # 获得的奖励 = 点赞总数 + 打赏总数
    payrecord = Payrelation.objects.filter(workid=work)
    paynum = len(payrecord) * work.getpaid
    response['rewardNum'] = work.attitudenum + paynum
    response['ok'] = 1
    return response

# 获取标签信息：包括标签名以及标签下的作品数量


def getTagInfo(tagid):
    response = {'ok': 0, 'msg': ''}
    response['tagid'] = tagid
    response['tagname'] = Tagreflect.objects.get(tagid=tagid).tag
    # 获取标签下的作品数量
    response['worknums'] = len(Tagwork.objects.filter(tagid=tagid))
    response['ok'] = 1
    return response

# 获取帖子列表


def getWorkList(userid, type, page, num, groupid, tagid):
    '''
    type: 1.我关注的圈子里所有（时间），2.一个圈子，3一个tag,4.我的 (按照时间排序)
    5,一个圈子 6,一个话题（按照热度） 7.我关注的圈子里所有（热度）
    groupid, tag 可选
    '''
    page = int(page)
    num = int(num)
    type = int(type)
    groupid = int(groupid)
    user = User.objects.get(userid=userid)
    response = {'ok': 0, 'msg': ''}
    workList = []
    max_num = 0

    works = Work.objects.none()  # 创建空集合

    # 我关注的圈子里所有
    if type == 1 or type == 7:
        groups = Grouprelation.objects.filter(userid=user).exclude(groupid=1)
        for group in groups:
            works = works | Work.objects.filter(groupid=group.groupid, status=0)  # 求并集

    # 一个圈子里所有
    if (type == 2) | (type == 5):
        works = Work.objects.filter(groupid=groupid, status=0)

    # 一个tag下的所有
    if (type == 3) | (type == 6):
        tagworks = Tagwork.objects.filter(tagid=tagid)
        works = Work.objects.none()
        for tagwork in tagworks:
            works = works | Work.objects.filter(workid=tagwork.workid.workid, status=0)

    # 我的作品
    if type == 4:
        works = Work.objects.filter(userid=userid, status=0)

    if (type == 5) | (type == 6) | (type == 7):
        works = works.order_by("-attitudenum")  # 按评论+点赞数排
    else:
        works = works.order_by("-releasetime")  # 按时间逆序

    paginator = Paginator(works, num)
    works_page = paginator.page(page)   # 分页 从1开始
    max_num = paginator.count

    for work in works_page:
        workList.append(getWorkInfo(userid, work.workid, 1))

    response['workList'] = workList
    response['max'] = max_num
    response['ok'] = 1

    return response


def search(userid, keyword, type, page, num):
    '''
    type: 0.搜用户，1.搜帖子 2.搜圈子，3.搜标签
    '''
    type = int(type)
    page = int(page)
    num = int(num)
    user = User.objects.get(userid=userid)
    response = {'ok': 0, 'msg': ''}
    worklist = []
    userlist = []
    taglist = []
    grouplist = []
    max_num = 0

    # 搜用户：直接根据用户名来搜索
    if type == 0:
        users = User.objects.filter(username__icontains=keyword, status=0)
        users = users.order_by("-fansNum")      # 按时间逆序

        paginator = Paginator(users, num)
        users_page = paginator.page(page)   # 分页 从1开始
        max_num = paginator.count

        for usr in users_page:
            userlist.append(getUserInfo(usr.userid, userid))

        response['userList'] = userlist
        response['max'] = max_num
        response['ok'] = 1
        return response

    # 搜帖子：根据标签、内容、标题搜索
    if type == 1:
        # 搜标签
        tagrfs = Tagreflect.objects.filter(tag__icontains=keyword)
        tagworks = Tagwork.objects.none()  # 创建空集合
        for tagrf in tagrfs:
            tagworks = tagworks | Tagwork.objects.filter(
                tagid=tagrf.tagid)  # 求并集
        works = Work.objects.none()
        for tagwork in tagworks:
            works = works | Work.objects.filter(workid=tagwork.workid.workid, status=0)
        # 搜标题
        works = works | Work.objects.filter(title__icontains=keyword, status=0)
        # 搜内容
        works = works | Work.objects.filter(text__icontains=keyword, status=0)
        works = works.order_by("-releasetime")      # 按时间逆序

        paginator = Paginator(works, num)
        works_page = paginator.page(page)   # 分页 从1开始
        max_num = paginator.count

        for work in works_page:
            worklist.append(getWorkInfo(userid, work.workid, 1))

        response['workList'] = worklist
        response['max'] = max_num
        response['ok'] = 1
        return response

    # 搜圈子：根据圈子名称和描述搜
    if type == 2:
        groups = Community.objects.filter(groupname__icontains=keyword)
        groups = groups | Community.objects.filter(
            description__icontains=keyword).exclude(groupid=1)
        groups = groups.order_by("-createtime")
        paginator = Paginator(groups, num)
        groups_page = paginator.page(page)   # 分页 从1开始
        max_num = paginator.count

        for group in groups_page:
            grouplist.append(getGroupMessage(group.groupid, userid))

        response['groupList'] = grouplist
        response['max'] = max_num
        response['ok'] = 1
        return response

    # 搜标签：直接根据tag名来搜索
    if type == 3:
        tagrfs = Tagreflect.objects.filter(tag__icontains=keyword)
        tagrfs = tagrfs.order_by("tag")

        paginator = Paginator(tagrfs, num)
        tagrfs_page = paginator.page(page)   # 分页 从1开始
        max_num = paginator.count

        for tagrf in tagrfs_page:
            taglist.append(getTagInfo(tagrf.tagid))

        response['tagList'] = taglist
        response['max'] = max_num
        response['ok'] = 1
        return response


def discover(userid, type, page, num):
    # type1: 发现页面 关注 帖子一级列表
    # type2: 发现页面 推荐 帖子一级列表
    # type3:  发现页面 圈子 列表
    # type4:  发现页面 话题 列表
    type = int(type)
    page = int(page)
    num = int(num)
    user = User.objects.get(userid=userid)
    response = {'ok': 0, 'msg': ''}
    worklist = []
    taglist = []
    grouplist = []
    max_num = 0
    # 我的关注下的所有
    if type == 1:
        mycares = Follow.objects.filter(follower=userid)
        works = Work.objects.none()

        for mycare in mycares:
            works = works | Work.objects.filter(userid=mycare.userid, status=0)

        works = works.order_by("-releasetime")  # 按时间逆序

        paginator = Paginator(works, num)
        works_page = paginator.page(page)   # 分页 从1开始
        max_num = paginator.count

        for work in works_page:
            worklist.append(getWorkInfo(userid, work.workid, 1))

        response['workList'] = worklist
        response['max'] = max_num
        response['ok'] = 1

        return response

    # 推荐算法
    if type == 2:
        # 推荐算法
        # 暂且与1相同 （请删除上方 or type == 2）
        response = getRecommendedPost(userid, 20)
        response['max'] = len(response['workList'])
        return response

    # 圈子
    if type == 3:
        groups = Community.objects.filter(status=0).exclude(groupid=1)
        groups = groups.order_by("-createtime")
        paginator = Paginator(groups, num)
        groups_page = paginator.page(page)   # 分页 从1开始
        max_num = paginator.count

        for group in groups_page:
            grouplist.append(getGroupMessage(group.groupid,userid))

        response['groupList'] = grouplist
        response['max'] = max_num
        response['ok'] = 1
        
        return response

    # 话题
    if type == 4:
        tagrfs = Tagreflect.objects.all()
        tagrfs = tagrfs.order_by("tag")

        # paginator = Paginator(tagrfs, num)
        # tagrfs_page = paginator.page(page)   # 分页 从1开始
        # max_num = paginator.count

        for tagrf in tagrfs:
            taglist.append(getTagInfo(tagrf.tagid))

        # 按作品数量排序
        taglist = sorted(taglist, key=lambda x: x['worknums'], reverse=True)

        # 最多取前30条，不分页
        taglist = taglist[:min(30, len(taglist))]
        max_num = len(taglist)
        # state 0：爆   1：热   2：荐
        for item in taglist:
            if item['worknums'] > 1000:
                item['state'] = 0
            elif item['worknums'] > 100:
                item['state'] = 1
            else:
                item['state'] = 4

        response['tagList'] = taglist
        response['max'] = max_num
        response['ok'] = 1
        return response


# 获取数量为number的对userid用户的推荐贴子
# userid: 当前用户, number: 推荐贴子的数量
def getRecommendedPost(userid, number):
    response = {'ok': 0, 'msg': ''}
    # 获取这个用户的权重
    user = User.objects.get(userid=userid)
    workList = []
    # 结果贴子和结果贴子对应的分数列表
    # result:存储的是最终推荐结果的workid
    result_workid = []
    # result_mark: 以分数为键,以对应result里的作品的序号为值
    result_mark = []

    # 对所有贴子进行遍历,过滤自己的帖子
    all_work = Work.objects.filter(status=0).exclude(userid=user)
    for work in all_work:

        # 对贴子列表中的每一个贴子进行评分
        work_mark = user.followweight * getFollowMark(userid, work.userid.userid) + \
                    user.groupweight * getGroupMark(userid, work.groupid.groupid) + \
                    user.heatweight * getHeatMark(work.attitudenum, work.commentnum) + \
                    user.paidweight * getPaidMark(work.getpaid) + \
                    user.tagweight * getTagMark()
        time_mark = getTimeMark(work.releasetime)
        # 贴子本身结合时间进行55开评分，确保推荐的实时性
        mark = 0.5 * work_mark + 0.5 * time_mark

        # 前1-number个贴子直接加入列表
        if len(result_workid) < number:
            result_workid.append(work.workid)
            result_mark.append(mark)

            continue

        # 恰好已经放入前number个贴子：分数排序后和分数最低的比较
        if len(result_workid) == number:
            sortList2(result_workid, result_mark, number)

        # 和当前得分最低的推荐贴比较，如果得分不够，则忽略这个贴子
        if mark <= result_mark[0]:
            continue

        result_mark[0] = mark
        result_workid[0] = work.workid
        sortList2(result_workid, result_mark, number)

    ###############################################################
    # 循环到这里结束后应该result_workid里就是我们想要推荐的贴子了，可接前端 #
    ###############################################################
    '''
        type: 1.我关注的圈子里所有（时间），2.一个圈子，3一个tag,4.我的 (按照时间排序)
        5,一个圈子 6,一个话题（按照热度） 7.我关注的圈子里所有（热度）
        groupid, tag 可选
        '''
    # max_num = number
    for wid in result_workid:
        workList.append(getWorkInfo(userid, wid, 1))

    response['workList'] = workList
    # response['max'] = max_num
    response['ok'] = 1

    return response


def getFollowMark(userid, postuserid):
    record = Follow.objects.filter(userid=postuserid, follower=userid)
    if len(record) == 0:
        return 0
    else:
        return 100


# 计算关注圈子对用户的影响权重
# 贴子为用户关注的圈子则100分，不是关注用户则记0分
# userid:当前用户id，groupid:贴子所在圈子的id
def getGroupMark(userid, groupid):
    record = Grouprelation.objects.filter(userid=userid, groupid=groupid)
    if len(record) == 0:
        return 0
    else:
        return 100


# 计算贴子热度对用户的影响权重
# attitudeNum:点赞数量, commentNum:评论的数量
def getHeatMark(attitudeNum, commentNum):
    attitudeMark = 0
    commentMark = 0
    # 点赞的评分机制如下:[10赞内0-25,100赞内10-100,500赞内50-75,1000赞内75-100，大于1000赞满分]
    if attitudeNum <= 10:
        attitudeMark = attitudeNum / 10 * 25
    elif attitudeNum <= 100:
        attitudeMark = (attitudeNum - 10) / 90 * 25 + 25
    elif attitudeNum <= 500:
        attitudeMark = (attitudeNum - 100) / 400 * 25 + 75
    elif attitudeNum <= 1000:
        attitudeMark = (attitudeNum - 500) /500 * 25 + 75
    else:
        attitudeMark = 100
    # 评论的评分机制如下[10回复内0-50,50回复内50-100,大于50回复满分]
    if commentNum <= 10:
        commentMark = commentNum / 10 * 50
    elif commentNum <= 50:
        commentMark = (commentNum - 10) / 40 * 50 + 50
    else:
        commentMark = 100
    # 贴子热度的评判: 70%点赞+30%评论
    return 0.7 * attitudeMark + 0.3 * commentMark


# 计算贴子收费对用户的影响权重
# getPaid: 获得贴子需要的鸭蛋数量
def getPaidMark(getPaid):
    if getPaid <= 10:
        return getPaid / 10 * 100
    else:
        return 0


# 计算标签对用户的影响权重
def getTagMark():
    ##################################
    # 我不会啊啊啊啊啊啊啊啊爸爸们救命救命 #
    ##################################
    return 100


# 计算贴子发布时间给贴子带来的评分
# 评分机制如下:[1小时内100,今天内80-100,3天内60-80,
# 1周内40-60,1月内20-40,3月内0-20,更久0分]
# 各个分数段中是个均匀分布
# releaseTime:贴子的发布时间
def getTimeMark(releaseTime):
    now_day = datetime.datetime.now()
    release_day = releaseTime
    # release_day = datetime.datetime.fromtimestamp(releaseTime)
    # release_day = now_day - datetime.timedelta(hours=now_day.hour, minutes=now_day.minute,
    #                                      seconds=now_day.second, microseconds=now_day.microsecond)
    difference = now_day - release_day
    # 先根据天数进行判断:当天的贴子 80-100
    if difference.days < 1:
        hours = difference.seconds // 3600
        return (24 - hours) / 24 * 20 + 80
    # 非当天的贴子,但三天内的贴子 60-80
    elif difference.days <= 3:
        hours = difference.seconds // 3600 - 24
        return (48 - hours) / 48 * 20 + 60
    # 非三天内的贴子，一周内的贴子 40-60
    elif difference.days <= 7:
        return (7 - difference.days) / 4 * 20 + 40
    # 非一周内的贴子，一个月内的贴子 20-40
    elif difference.days <= 30:
        return (30 - difference.days) / 23 * 20 + 20
    elif difference.days <= 90:
        return (90 - difference.days) / 60 * 20
    # 超过三个月的贴子 0分
    else:
        return 0


# 辅助函数:长度为n的list1和list2保持下标一一对应关系
# 对list2进行从小到大排序
def sortList2(list1, list2, n):
    # 插入排序，同时变动list1的值使得下表一致
    for i in range(1, n):
        key2 = list2[i]
        key1 = list1[i]
        j = i - 1
        while j >= 0 and key2 < list2[j]:
            list2[j + 1] = list2[j]
            list1[j + 1] = list1[j]
            j -= 1
        list2[j + 1] = key2
        list1[j + 1] = key1


# 当用户在推荐界面喜欢一个贴子后的反馈调整函数
# 根据用户行为调整权重
# userid: 点赞人用户id，workid: 被点赞的贴子
def feedback(userid, workid):
    response = {'ok': 0, 'msg': ''}
    # 获取这个用户的权重
    user = User.objects.get(userid=userid)
    work = Work.objects.get(workid=workid)
    # 计算这个贴子的影响权重
    follow_mark = getFollowMark(userid, work.userid.userid)
    group_mark = getGroupMark(userid, work.groupid.groupid)
    heat_mark = getHeatMark(work.attitudenum, work.commentnum)
    paid_mark = getPaidMark(work.getpaid)
    tag_mark = getTagMark()
    mark = follow_mark + group_mark + heat_mark + paid_mark + tag_mark

    # 新权重:90%旧权重+10%新权重
    user.followweight = user.followweight * 0.9 + follow_mark / mark * 0.1
    user.groupweight = user.groupweight * 0.9 + group_mark /mark * 0.1
    user.heatweight = user.heatweight * 0.9 + heat_mark / mark * 0.1
    user.paidweight = user.paidweight * 0.9 + paid_mark / mark * 0.1
    user.tagweight = user.tagweight * 0.9 + tag_mark / mark * 0.1

    response['ok'] = 1
    response['msg'] = '调整权值成功'
    # 更新
    user.save()
    return response